﻿using System.Collections.Generic;
using System.Linq;
using System.Text;
using JetBrains.Annotations;
using Missbot.AIModule.Base;
using Missbot.Common;
using Missbot.Common.Net;
using Missbot.Core.Base;

namespace Missbot.AIModule.Tuling
{
    [UsedImplicitly]
    public class TulingMod : IAIModule, IDataMgr
    {
        public override string Name => "图灵";
        public override AIPriority Priority => AIPriority.Low;

        private const string RequestUrl = "http://openapi.tuling123.com/openapi/api/v2";
        private List<TulingConfig> ApiKeys = new();

        /// <summary>
        /// 每日图灵限制
        /// </summary>
        private const int TulingDailyLimit = 20;

        private static InstanceConfig InstanceConfig => Configger<AIConfigBase>.AIConfig.Instance;

        /// <summary>
        /// 当前图灵api索引
        /// </summary>
        private int CurTulingIndex;

        /// <summary>
        /// 错误码
        /// </summary>
        private readonly int[] ErroCodes =
        {
            5000, 6000, 4000, 4001, 4002, 4003, 4005, 4007, 4100, 4200, 4300, 4400, 4500, 4600, 4602, 7002, 8008
        };

        protected override bool OnInboxImpl(InboxSession session)
        {
            if (base.OnInboxImpl(session))
            {
                return true;
            }

            if (session.Text == null || !session.Text.Contains($"@{InstanceConfig.BotUserName} "))
            {
                return false;
            }

            session.Text = session.Text.Replace($"@{InstanceConfig.BotUserName} ", "");

            var limitRecord = DailyLimitDA.Get(session.User.ID, "Tuling");
            if (!limitRecord.Check(TulingDailyLimit))
            {
                session.SendBack("今天太累了，明天再找我说话吧~");
                return false;
            }

            limitRecord.Cache();
            limitRecord.Update();

            string response = null;
            foreach (var tuling in ApiKeys.Select(_ => ApiKeys[CurTulingIndex]))
            {
                response = RequestMsg(session, tuling.ApiKey);
                if (!string.IsNullOrEmpty(response))
                {
                    break;
                }

                CurTulingIndex = (CurTulingIndex + 1) % ApiKeys.Count;
            }

            if (string.IsNullOrEmpty(response))
            {
                session.SendBack("今天太累了，明天再找我说话吧~");
                return false;
            }

            session.SendBack(response);
            return true;
        }

        public void RefreshData()
        {
            ApiKeys = TulingConfigDA.GetAll();
        }

        /// <summary>
        /// 获取图灵返回值
        /// </summary>
        /// <param name="session"></param>
        /// <param name="ApiKey"></param>
        /// <returns></returns>
        private string RequestMsg(InboxSession session, string ApiKey)
        {
            var post = GetPostReq(session, ApiKey);
            if (post == null)
            {
                return string.Empty;
            }

            var response = HttpRequestor.PostData<TulingResponseData>(RequestUrl, post);
            if (response == null || ErroCodes.Contains(response.Intent.Code))
            {
                return string.Empty;
            }

            return ParseResponse(response);
        }

        /// <summary>
        /// 获取图灵请求
        /// </summary>
        /// <param name="session"></param>
        /// <param name="ApiKey"></param>
        /// <returns></returns>
        private TulingRequestData GetPostReq(InboxSession session, string ApiKey)
        {
            var perception = new PerceptionData { InputText = new InputTextData { Text = session.Text } };

            return new TulingRequestData
            {
                ReqType = 0,
                Perception = perception,
                UserInfo = new UserInfoData { ApiKey = ApiKey, UserId = session.User.ID }
            };
        }

        /// <summary>
        /// 解析图灵返回值
        /// </summary>
        /// <param name="response"></param>
        /// <returns></returns>
        private static string ParseResponse(TulingResponseData response)
        {
            var result = string.Empty;
            var builder = new StringBuilder();
            builder.Append(result);
            foreach (var res in response.Results)
            {
                var str = res.ResultType switch
                {
                    "text" => res.Values.Text,
                    "url" => $" {res.Values.Url} ",
                    _ => null
                };

                builder.Append(str);
            }

            result = builder.ToString();
            return result;
        }
    }
}